package cn.t.facade.industry;


import cn.t.constants.CommonConstants;
import cn.t.converter.industry.IndustryWorkOrderConverter;
import cn.t.converter.user.UserInfoRequestConverter;
import cn.t.core.exception.BizException;
import cn.t.dto.user.CostCenterDTO;
import cn.t.dto.user.CreateUserRequest;
import cn.t.dto.user.CustomerFirmDTO;
import cn.t.dto.user.CustomerIndividualDTO;
import cn.t.dto.user.ParticipantInfoDTO;
import cn.t.dto.user.RoleInfoDTO;
import cn.t.dto.user.UserInfoDTO;
import cn.t.dto.user.UserPassportDTO;
import cn.t.enums.order.ErrorEnum;
import cn.t.enums.order.WorkOrderTypeEnum;
import cn.t.enums.order.WorkStatusEnum;
import cn.t.facade.user.CostCenterFacade;
import cn.t.facade.user.CustomerFirmFacade;
import cn.t.facade.user.CustomerInfoFacade;
import cn.t.facade.user.UserInfoFacade;
import cn.t.model.IndustryUserInfoDO;
import cn.t.model.order.WorkOrderDO;
import cn.t.model.order.WorkOrderDetailDO;
import cn.t.model.sku.SkuDO;
import cn.t.model.user.RoleFirmDO;
import cn.t.request.industry.IndustryCreateWorkOrderReq;
import cn.t.service.IndustryUserInfoService;
import cn.t.service.order.WorkOrderDetailService;
import cn.t.service.order.WorkOrderService;
import cn.t.service.sku.SkuService;
import cn.t.service.user.RoleFirmService;
import cn.t.utils.DateUtil;
import cn.t.utils.DesensitizationUtil;
import cn.t.vo.industry.IndustryApplyOrderVO;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 工单服务编排
 */
@Slf4j
@Service
@AllArgsConstructor
public class IndustryWorkOrderFacade {

    private final WorkOrderService workOrderService;
    private final WorkOrderDetailService workOrderDetailService;
    private final UserInfoRequestConverter userInfoRequestConverter;
    private final CustomerInfoFacade customerInfoFacade;
    private final UserInfoFacade userInfoFacade;
    private final CustomerFirmFacade customerFirmFacade;
    private final SkuService skuService;
    private final CostCenterFacade costCenterFacade;
    private final IndustryUserInfoService industryUserInfoService;
    private final IndustryWorkOrderConverter industryWorkOrderConverter;
    private final RoleFirmService roleFirmService;

    @Transactional(rollbackFor = Exception.class)
    public String createWorkOrder(IndustryCreateWorkOrderReq request) {

        // 校验是否留过资
        IndustryUserInfoDO industryUserInfoDO = this.industryUserInfoService.getIndustryUserInfo(request.getPhoneNumber());
        if (industryUserInfoDO != null) {
            throw new BizException(ErrorEnum.DATA_ALREADY_EXISTS, "您已申领过礼品, 请前往[智能柜]领取！");
        }

        // 获取工单号
        String workOrderSn = this.workOrderService.getWorkOrderSn(CommonConstants.WORK_START_DEFAULT);

        // 1.创建默认公司
        CustomerFirmDTO customerFirmDTO = this.customerFirmFacade.queryFirmByCode(CommonConstants.INDUSTRY_UNIFY_CUSTOMER_CODE);
        if (customerFirmDTO == null) {
            customerFirmDTO = new CustomerFirmDTO();
            customerFirmDTO.setFirmCode(CommonConstants.INDUSTRY_UNIFY_CUSTOMER_CODE);
            customerFirmDTO.setFirmName(CommonConstants.INDUSTRY_UNIFY_CUSTOMER_NAME);
            Long firmId = this.customerInfoFacade.createFirm(customerFirmDTO);
            customerFirmDTO.setId(firmId);
        }

        // 绑定成本中心 工单尽量平均分配到4个成本中心
        List<CostCenterDTO> costCenterDTOs = costCenterFacade.findCostCenter(customerFirmDTO.getId());
        // 查询工单 向前推6个月（尽量查询所有工单，假设这个量不会太大）
        List<WorkOrderDO> workOrders = workOrderService.firstPage(customerFirmDTO.getId(), DateUtil.afterMonth(LocalDateTime.now(), -6), Integer.MAX_VALUE).stream().filter(f -> !ObjectUtils.isEmpty(f.getCostCenterId())).collect(Collectors.toList());

        // 根据成本中心分组统计
        Map<Long, Long> costCentWorkOrderNumMap = workOrders.stream().collect(Collectors.groupingBy(WorkOrderDO::getCostCenterId, Collectors.counting()));
        Long selectedCostCenterId = null;
        // 如果成本中心没有被用过,直接使用这个成本中心
        for (CostCenterDTO costCenterDTO:costCenterDTOs) {
            if (!costCentWorkOrderNumMap.containsKey(costCenterDTO.getId())) {
                selectedCostCenterId = costCenterDTO.getId();
                break;
            }
        }

        // 成本中心都使用过了,选择使用最少的那个成本中心
        if (selectedCostCenterId == null) {
            selectedCostCenterId = costCentWorkOrderNumMap.entrySet().stream().min(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);
        }


        // 2.创建领料人
        CreateUserRequest createUserRequest = new CreateUserRequest();
        createUserRequest.setUserName(request.getPhoneNumber());
        createUserRequest.setPhoneNumber(request.getPhoneNumber());
        createUserRequest.setIndividualName(request.getNickname());
        createUserRequest.setCostCenterId(selectedCostCenterId);

        Map<Integer, UserPassportDTO> passportMap = userInfoRequestConverter.convertPassport(createUserRequest);
        UserInfoDTO userInfo = userInfoRequestConverter.convertUserInfo(createUserRequest);
        CustomerIndividualDTO customerIndividual = userInfoRequestConverter.convertCustomerInfo(createUserRequest);

        // 绑定领料员
        List<RoleFirmDO> roleFirmList = roleFirmService.list(customerFirmDTO.getId());
        if (!CollectionUtils.isEmpty(roleFirmList)) {
            createUserRequest.setRoleId(roleFirmList.get(0).getRoleId());
        }

        RoleInfoDTO roleInfoDTO = userInfoRequestConverter.convertRoleInfoDTO(createUserRequest);
        //成本中心绑定
        ParticipantInfoDTO participantInfoDTO = userInfoRequestConverter.convertParticipantInfo(createUserRequest);

        UserInfoDTO userInfoDTO = this.userInfoFacade.create(passportMap, userInfo, participantInfoDTO,roleInfoDTO, customerIndividual, customerFirmDTO);

        // 3.创建领料工单
        this.createWorkOrder(request, userInfoDTO.getId(), customerFirmDTO.getId(), workOrderSn, selectedCostCenterId);

        // 4. 记录留资信息
        industryUserInfoDO = this.industryWorkOrderConverter.req2IndustryUserDo(request, workOrderSn, userInfoDTO.getId());
        industryUserInfoDO.setCreator(String.valueOf(userInfoDTO.getId()));
        industryUserInfoDO.setModifier(String.valueOf(userInfoDTO.getId()));
        this.industryUserInfoService.add(industryUserInfoDO);
        return workOrderSn;
    }

    private void createWorkOrder(IndustryCreateWorkOrderReq request, Long userId, Long firmId, String workOrderSn, Long costCentId)  {

        //工单头表
        WorkOrderDO workOrderDO = new WorkOrderDO();
        workOrderDO.setWorkOrderSn(workOrderSn);
        workOrderDO.setFirmId(firmId);
        workOrderDO.setDocType(WorkOrderTypeEnum.PICK.getCode());
        workOrderDO.setAbnormalFlag(CommonConstants.ZERO);
        workOrderDO.setNickname(request.getNickname());
        workOrderDO.setCreator(String.valueOf(userId));
        workOrderDO.setModifier(String.valueOf(userId));
        workOrderDO.setCostCenterId(costCentId);
        workOrderDO.setStatus(WorkStatusEnum.WAIT_DO.getCode());
        workOrderDO.setWorkOrderSource(CommonConstants.ONE);

        // 根据客户定制化设置工单数据
        this.workOrderService.customizeWorkOrder(workOrderDO, CommonConstants.INDUSTRY_UNIFY_CUSTOMER_CODE);

        this.workOrderService.add(workOrderDO);

        // 获取商品map
        List<SkuDO> skuDOS = this.skuService.findModelList(Lists.newArrayList(request.getSkuCode()));

        if (!CollectionUtils.isEmpty(skuDOS)) {
            // 插入明细表
            WorkOrderDetailDO workOrderDetailDO = new WorkOrderDetailDO();
            SkuDO skuDO = skuDOS.get(0);
            workOrderDetailDO.setWorkOrderSn(workOrderSn);
            workOrderDetailDO.setSkuCode(request.getSkuCode());
            workOrderDetailDO.setSkuName(skuDO.getSkuName());
            workOrderDetailDO.setSkuImg(skuDO.getSkuImg());
            workOrderDetailDO.setPlanQty(request.getQty());
            workOrderDetailDO.setCreator(String.valueOf(userId));
            workOrderDetailDO.setModifier(String.valueOf(userId));
            this.workOrderDetailService.add(workOrderDetailDO);
        }
    }

    public List<IndustryApplyOrderVO> getApplyOrder(Integer count, Long firmId) {
        // 倒序查询工单
        List<WorkOrderDO> workOrders = this.workOrderService.firstPage(firmId, null, count);
        List<String> workOrderSns = workOrders.stream().map(WorkOrderDO::getWorkOrderSn).collect(Collectors.toList());
        // 查询工单明细
        List<WorkOrderDetailDO> workOrderDetails = this.workOrderDetailService.getWorkOrderDetails(null, null, workOrderSns);
        Map<String, List<WorkOrderDetailDO>> workOrderDetailMap = workOrderDetails.stream().collect(Collectors.groupingBy(WorkOrderDetailDO::getWorkOrderSn));

        List<IndustryApplyOrderVO> industryApplyOrders = new ArrayList<>();
        workOrders.forEach(wo -> {
            List<WorkOrderDetailDO> curWorkOrderDetails = workOrderDetailMap.get(wo.getWorkOrderSn());
            if (CollectionUtils.isEmpty(curWorkOrderDetails)) {
                return;
            }
            List<IndustryApplyOrderVO.Sku> skuList = new ArrayList<>();
            curWorkOrderDetails.forEach(od -> skuList.add(new IndustryApplyOrderVO.Sku(od.getSkuCode(), od.getSkuName(), od.getSkuImg(), od.getPlanQty())));

            int total = skuList.stream().mapToInt(IndustryApplyOrderVO.Sku::getSkuNum).sum();
            industryApplyOrders.add(new IndustryApplyOrderVO(wo.getGmtCreated(), DesensitizationUtil.generate(1, wo.getNickname(), 1, 1) , wo.getWorkOrderSn(), skuList, total));
        });
        return industryApplyOrders;
    }
}

